#include "sensor.h"

int32_t offset = 0; // offset value for ZERO calibration
//float scale = 2.3420119e-6; // 1号传感器
float scale = 2.42771e-6;//2号传感器
int32_t last_raw_value = 0; // last value read from the CS1237

void cs1237_delay() //delay at least 0.2us
{
    uint32_t i = 0;
    for (i = 0; i < 1; i++)
    {
        __NOP(); // do nothing
    }
}

/**
 * @brief  Initialize the CS1237 ADC.
 * @note This function configures the CS1237 ADC for 640Hz speed, and PGA gain of 128.
 */
void CS1237_Init(void)
{
    HAL_Delay(3);  // 等待芯片稳定

    // 关闭SPI功能
    HAL_SPI_DeInit(&hspi3);
    // 禁用外部中断
    HAL_NVIC_DisableIRQ(EXTI15_10_IRQn); 
    // 配置PC10为输出模式，PC11为输入模式
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = GPIO_PIN_10; // SCLK
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 设置为推挽输出
    GPIO_InitStruct.Pull = GPIO_NOPULL; // 无上下拉电阻
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM; // 设置为中速
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); // 初始化PC10
    GPIO_InitStruct.Pin = GPIO_PIN_11; // MISO
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT; // 设置为输入模式
    GPIO_InitStruct.Pull = GPIO_NOPULL; // 无上下拉电阻
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); // 初始化PC11

    // 等待PC11低电平
    while (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_11) == GPIO_PIN_SET) 
    {
        cs1237_delay();
    }

    // 用29个CLK使能CS1237的输入配置模式
    for (int i = 1; i <= 29; i++) 
    {
        // 发送时钟信号
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_SET); // SCLK高电平
        cs1237_delay();// 延时
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_RESET); // SCLK低电平
        cs1237_delay();// 延时
    }

    //切换PC11为输出模式
    HAL_GPIO_DeInit(GPIOC, GPIO_PIN_11); // 先去初始化PC11
    GPIO_InitStruct.Pin = GPIO_PIN_11; // MISO
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 设置为推挽输出
    GPIO_InitStruct.Pull = GPIO_NOPULL; // 无上下拉电阻
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); // 初始化PC11为输出模式

    // 发送CS1237配置写入命令字
    uint8_t bit_filter = 0x40;
    for (int i = 30; i <= 36; i++) 
    {
        
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_SET); // SCLK高电平
        cs1237_delay();// 延时

        if (bit_filter & CS1237_WRITE_CONFIG_CMD)
        {
            HAL_GPIO_WritePin(GPIOC, GPIO_PIN_11, GPIO_PIN_SET); // 发送1
        }
        else
        {
            HAL_GPIO_WritePin(GPIOC, GPIO_PIN_11, GPIO_PIN_RESET); // 发送0
        }
        bit_filter >>= 1; // 右移一位

        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_RESET); // SCLK低电平
        cs1237_delay();// 延时
    }

    // 第37个CLK，CS1237内部响应
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_SET); // SCLK高电平
    cs1237_delay();// 延时
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_RESET); // SCLK低电平
    cs1237_delay();// 延时

    // 第38-45个CLK，发送配置寄存器值
    bit_filter = (1 << 7);
    uint8_t config_value = CS1237_CH_SEL_CHANNELA | CS1237_SPEED_SEL_640HZ | CS1237_PGA_SEL_128;
    for (int i = 38; i <= 45; i++) 
    {
        if (bit_filter & config_value) // 第38个CLK发送配置寄存器值
        {
            HAL_GPIO_WritePin(GPIOC, GPIO_PIN_11, GPIO_PIN_SET); // 发送1
        }
        else
        {
            HAL_GPIO_WritePin(GPIOC, GPIO_PIN_11, GPIO_PIN_RESET); // 发送0
        }
        bit_filter >>= 1; // 右移一位

        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_SET); // SCLK高电平
        cs1237_delay();// 延时

        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_RESET); // SCLK低电平
        cs1237_delay();// 延时
    }

    // 第46个CLK，CS1237内部切换DRDY#/DOUT引脚为输出模式
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_SET); // SCLK高电平
    cs1237_delay();// 延时

    //切换PC11为外部中断模式
    HAL_GPIO_DeInit(GPIOC, GPIO_PIN_11); // 先去初始化PC11
    GPIO_InitStruct.Pin = GPIO_PIN_11; // MISO
    GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; // 设置为外部中断模式
    GPIO_InitStruct.Pull = GPIO_NOPULL; // 无上下拉电阻
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); // 初始化PC11为外部中断模式
    
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_RESET); // SCLK低电平
    cs1237_delay();// 延时

    HAL_NVIC_SetPriority(EXTI15_10_IRQn, 5, 0); // 设置外部中断优先级
    HAL_NVIC_EnableIRQ(EXTI15_10_IRQn); // 使能外部中断
}

int32_t CS1237_ReadData_EXTI(void)
{
    int32_t data = 0;
    uint8_t adc_raw[3] = {0};

    // 禁用外部中断，关闭PC10 PC11引脚
    HAL_NVIC_DisableIRQ(EXTI15_10_IRQn);
    HAL_GPIO_DeInit(GPIOC, GPIO_PIN_10 | GPIO_PIN_11);
    // 打开SPI功能
    HAL_SPI_Init(&hspi3);

    // 接收CS1237 ADC数据
    HAL_SPI_Receive(&hspi3, adc_raw, 3, 5); // 接收3字节数据
    // 组合24位数据 (大端格式)
    data = (adc_raw[0] << 16) | (adc_raw[1] << 8) | adc_raw[2];

    if ((data & 0x800000) == 0x800000) // if the data is negative
    {
        data |= 0xFF000000; // sign extend to 32 bits
    }

    // 关闭SPI功能
    HAL_SPI_DeInit(&hspi3);
    // 配置PC11引脚为外部中断模式, PC10引脚为输出低电平
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = GPIO_PIN_11;
    GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; // set the pin back to interrupt mode
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); // set the pin to interrupt mode
    HAL_NVIC_SetPriority(EXTI15_10_IRQn, 5, 0); // set the interrupt priority    
    HAL_NVIC_EnableIRQ(EXTI15_10_IRQn); // enable the interrupt
    GPIO_InitStruct.Pin = GPIO_PIN_10; // SCLK
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 设置为推挽输出
    GPIO_InitStruct.Pull = GPIO_NOPULL; // 无上下拉电阻
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM; // 设置为中速
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); // 初始化PC10为输出模式
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_RESET); // SCLK低电平

    last_raw_value = data; // 保存最后一次读取的原始数据
    return data;
}

/**
 * @brief  Set the offset for zero calibration.
 */
void CS1237_Set_Offset(float offset_value)
{
    // set the offset for zero calibration 
    // offset = offset_value * (1 / 9.8015f) / scale; 
    offset = (int32_t)(offset_value * 0.102025 / scale); // convert weight to raw value
}

/**
 * @brief  Set the scale factor for weight conversion.
 * @param weight: Unit kg. The weight to be used for calibration. 
 **/
float CS1237_Set_Scale(float weight)
{
    // set the scale factor for weight conversion
    int32_t raw_value = last_raw_value - offset;
    if (raw_value == 0)
    {
        raw_value = 1; // avoid division by zero
    }
    scale = weight / (float)raw_value;
//printf("hx711_scale_raw = %d\r\n", hx711_last_raw_value);
    return scale;
}

/**
 * @brief  Read the weight from the CS1237.
 * @retval The weight in kg.
 **/
float CS1237_Read_Kg(void)
{
    int32_t raw_value = last_raw_value - offset;
    float weight = (float)raw_value * scale;
    return weight;
}

/**
 * @brief  Read the weight from the CS1237 in Newtons.
 * @retval The weight in Newtons.
 */
float CS1237_Read_N(void)
{
    int32_t raw_value = last_raw_value - offset;
    float weight = (float)raw_value * scale * 9.8015f; // Convert to N
    return weight;
}
